/*
	Copyright (C) 2011 Daniel C. Dennison (dandennison84@gmail.com).  All rights reserved.
	This file is licensed under the EPL 1.0 (Eclipse Public License 1.0)
	A copy of the license can be found at http://www.eclipse.org/legal/epl-v10.html
*/

package com.gmail.dandennison84.accounting

import org.junit.Before
import org.junit.Test

class AccountTest {
	Account cashAccount, equipmentAccount
	Date today, yesterday, twoDaysAgo
	JournalEntry entryToday, entryYesterday

	@Before
	void before() {
		cashAccount = new Account(name:'Cash', accountType:AccountType.ASSETS, balanceType:BalanceType.DEBIT, closingType:ClosingType.PERMANENT,
			cashFlowStatementType:CashFlowStatementType.OPERATING_ACTIVITIES)
		equipmentAccount = new Account(name:'Equipment', accountType:AccountType.ASSETS, balanceType:BalanceType.DEBIT, closingType:ClosingType.PERMANENT,
			cashFlowStatementType:CashFlowStatementType.OPERATING_ACTIVITIES)
		today = new Date()
		yesterday = today - 1
		twoDaysAgo = yesterday - 1
		entryYesterday = new JournalEntry(id:1, description:'bought office equipment', dateTime:yesterday)
		entryToday = new JournalEntry(id:2, description:'more office equipment', dateTime:today)
		JournalEntryAmount cashForEquipment = new JournalEntryAmount(account:cashAccount, amount:5.0)
		JournalEntryAmount equipmentAmount = new JournalEntryAmount(account:equipmentAccount, amount:5.0)
		entryYesterday.credits << cashForEquipment
		entryYesterday.debits << equipmentAmount
		cashForEquipment = new JournalEntryAmount(account:cashAccount, amount:1.0)
		equipmentAmount = new JournalEntryAmount(account:equipmentAccount, amount:1.0)
		entryToday.credits << cashForEquipment
		entryToday.debits << equipmentAmount
	}

	@Test(expected=Throwable)
	void noName() {
		new Account(accountType:AccountType.ASSETS, closingType:ClosingType.PERMANENT, balanceType:BalanceType.DEBIT,
			cashFlowStatementType:CashFlowStatementType.OPERATING_ACTIVITIES)
	}

	@Test(expected=Throwable)
	void noAccountType() {
		new Account(name:'test', closingType:ClosingType.PERMANENT, balanceType:BalanceType.DEBIT, cashFlowStatementType:CashFlowStatementType.OPERATING_ACTIVITIES)
	}

	@Test(expected=Throwable)
	void noBalanceType() {
		new Account(name:'test', closingType:ClosingType.PERMANENT, accountType:AccountType.ASSETS, cashFlowStatementType:CashFlowStatementType.OPERATING_ACTIVITIES)
	}

	@Test(expected=Throwable)
	void noClosingType() {
		new Account(name:'test', balanceType:BalanceType.DEBIT, accountType:AccountType.ASSETS, cashFlowStatementType:CashFlowStatementType.OPERATING_ACTIVITIES)
	}

	@Test(expected=Throwable)
	void noCashFlowStatementType() {
		new Account(name:'test', closingType:ClosingType.TEMPORARY, balanceType:BalanceType.DEBIT, accountType:AccountType.ASSETS)
	}

	@Test
	void contraDefined() {
		Account contraAccount = new Account(name:'contra', accountType:AccountType.ASSETS, closingType:ClosingType.TEMPORARY, balanceType:BalanceType.CREDIT, contra:true,
			cashFlowStatementType:CashFlowStatementType.OPERATING_ACTIVITIES)
		cashAccount.contraAccount = contraAccount
		assert !cashAccount.contra
		assert contraAccount.contra
		assert cashAccount.contraAccount == contraAccount
	}

	@Test
	void testProperties() {
		assert cashAccount.properties.size() == 0
		cashAccount.properties['test'] = 'foobar'
		assert cashAccount.properties.size() == 1
		assert cashAccount.properties['test'] == 'foobar'
		Map p = [:]
		p['a'] = 'b'
		Account a = new Account(name:'Cash', accountType:AccountType.ASSETS, balanceType:BalanceType.DEBIT, closingType:ClosingType.PERMANENT, properties:p,
			cashFlowStatementType:CashFlowStatementType.OPERATING_ACTIVITIES)
		assert a.properties['a'] == 'b'
	}

	@Test
	void toStringMatches() {
		assert 'Cash [contra: false, accountType: ASSETS, balanceType: DEBIT, closingType: PERMANENT, groupName: null, contraAccount: null, properties: [:]]' == cashAccount.toString()
	}

	@Test
	void testNotPosted() {
		assert cashAccount.entries.size() == 0
	}

	@Test
	void testEntriesOn() {
		entryYesterday.post()
		entryToday.post()
		assert entryYesterday == cashAccount.getEntriesOn(yesterday)[0]
	}

	@Test
	void testEntriesTo() {
		entryYesterday.post()
		entryToday.post()
		assert entryYesterday == cashAccount.getEntriesOn(yesterday)[0]
	}

	@Test
	void testEntriesFrom() {
		entryYesterday.post()
		entryToday.post()
		assert entryToday == cashAccount.getEntriesFrom(today)[0]
	}

	@Test
	void testEntriesBetween() {
		entryYesterday.post()
		assert entryYesterday == cashAccount.getEntriesBetween(twoDaysAgo, yesterday)[0]
	}

	@Test
	void testEntriesNullBetween() {
		entryYesterday.post()
		assert entryYesterday == cashAccount.getEntriesBetween(null, null)[0]
	}

	@Test
	void testCompareTo() {
		assert cashAccount < equipmentAccount
	}

	@Test
	void testBalanceMethods() {
		entryYesterday.post()
		assert 5.0 == equipmentAccount.getDebitBalanceBetween(twoDaysAgo, today)
		assert 5.0 == cashAccount.getCreditBalanceBetween(twoDaysAgo, today)
		assert 0 == equipmentAccount.getDebitBalanceOn(today)
		assert 0 == cashAccount.getCreditBalanceOn(today)
		assert 5.0 == equipmentAccount.debitBalance
		assert 5.0 == cashAccount.creditBalance
		assert cashAccount < equipmentAccount
	}

	@Test
	void testBalanceTypesWithBalance() {
		Account a = new Account(name:'a', accountType:AccountType.ASSETS, balanceType:BalanceType.DEBIT, closingType:ClosingType.PERMANENT,
			cashFlowStatementType:CashFlowStatementType.OPERATING_ACTIVITIES)
		Account b = new Account(name:'b', accountType:AccountType.LIABILITIES, balanceType:BalanceType.CREDIT, closingType:ClosingType.PERMANENT,
			cashFlowStatementType:CashFlowStatementType.OPERATING_ACTIVITIES)
		JournalEntry je = new JournalEntry(id:1, description:'first', dateTime:today)
		JournalEntryAmount jea = new JournalEntryAmount(account:a, amount:3)
		je.debits << jea
		jea = new JournalEntryAmount(account:b, amount:3);
		je.credits << jea
		je.post()

		je = new JournalEntry(id:2, description:'second', dateTime:today)
		jea = new JournalEntryAmount(account:a, amount:2)
		je.credits << jea
		jea = new JournalEntryAmount(account:b, amount:2)
		je.debits << jea
		je.post()

		assert 1 == a.debitBalance - a.creditBalance
		assert 1 == b.creditBalance - b.debitBalance
	}
}
